package rpc

import (
	"fmt"
	"log"
	"net"
	"reflect"
	"strings"
	"time"
)

// Server 声明服务端
type Server struct {
	// 地址
	addr string
	// 服务端维护的函数名到函数反射值的map
	funcs map[string]reflect.Value
}

// NewServer 创建服务端对象
func NewServer(addr string) *Server {
	return &Server{addr: addr, funcs: make(map[string]reflect.Value)}
}

// Register 服务端绑定注册方法，将函数名与函数真正实现对应起来，第一个参数为函数名， 第二个传入真正的函数
func (s *Server) Register(rpcName string, f interface{}) {
	if _, ok := s.funcs[rpcName]; ok {
		return
	}
	// map中没有值，则将映射添加进map,便于调用
	fVal := reflect.ValueOf(f)
	s.funcs[rpcName] = fVal
}

// Run 服务端等待调用
func (s *Server) Run() {
	// 监听
	lis, err := net.Listen("tcp", s.addr)
	if err != nil {
		fmt.Printf("监听%s err:%v", s.addr, err)
		return
	}
	log.Printf("rpc server start ok, addr: %s", s.addr)
	for {
		// 拿到连接
		conn, err := lis.Accept()
		if err != nil {
			fmt.Printf("rpc server accept err:%v \n", err)
			continue
		}
		log.Printf("rpc server connect client success, remote addr: %s", conn.RemoteAddr())
		// 创建会话
		srvSession := NewSession(conn)
		// 使用协程处理rpc请求
		//go s.handleConnection(srvSession)
		go s.handlePooledConnection(srvSession)
	}
}

func (s *Server) handleConnection(srvSession *Session) {
	start := time.Now().UnixNano()
	// 析构函数关闭服务端连接
	defer func() {
		err := srvSession.Close()
		if err != nil {
			log.Println("close client conn fail, ", err)
		}
		end := time.Now().UnixNano()
		log.Printf("rpc server handler connect consume time: %d ns", end-start)
	}()
	// RPC 读取数据  update user set password=password('123456') where user='root' and host='localhost';
	bytes, err := srvSession.Read()
	if err != nil {
		log.Printf("server read data err: %v", err)
		return
	}
	// 对数据解码
	rpcData, err := decode(bytes)
	if err != nil {
		log.Printf("sever decode rpc data err: %v", err)
		return
	}
	// 根据读取到的数据的Name,得到调用的函数名
	f, ok := s.funcs[rpcData.Name]
	if !ok {
		log.Panicf("函数名%s不存在", rpcData.Name)
	}
	// 解析遍历客户端出来的参数, 放到一个数组中
	inArgs := make([]reflect.Value, 0, len(rpcData.Args))
	for _, arg := range rpcData.Args {
		inArgs = append(inArgs, reflect.ValueOf(arg))
	}
	// 反射调用方法，传入参数
	out := f.Call(inArgs)
	// 解析遍历执行结果，放到一个数组中
	outArgs := make([]interface{}, 0, len(out))
	for _, o := range out {
		outArgs = append(outArgs, o.Interface())
	}
	// 包装数据返回给客户端
	respRPCData := RPCData{rpcData.Name, outArgs}
	// 编码
	respBytes, err := encode(respRPCData)
	if err != nil {
		log.Printf("server rpc data encode err: %v", err)
		return
	}
	// 使用RPC写出数据
	err = srvSession.Write(respBytes)
	if err != nil {
		log.Printf("server rpc session write err: %v", err)
	}
}

func (s *Server) handlePooledConnection(srvSession *Session) {
	start := time.Now().UnixNano()
	// 析构函数关闭服务端连接
	defer func() {
		err := srvSession.Close()
		if err != nil {
			log.Println("close client conn fail, ", err)
		}
		end := time.Now().UnixNano()
		log.Printf("rpc server handler connect consume time: %d ns", end-start)
	}()

	var response Response
	for {
		// RPC 读取数据  update user set password=password('123456') where user='root' and host='localhost';
		bytes, err := srvSession.Read()
		if err != nil {
			log.Printf("server read data err: %v", err)
			if err.Error() == "EOF" { // ignore
				break
			}
			if strings.Contains(err.Error(), "connect reset by peer") { // disconnect
				break
			}
			response.Err = fmt.Sprintf("zerorpc request from addr:%s read err:%v", srvSession.remoteAddr, err)

			response.ResponseTimestamp = time.Now().UnixNano() // invoke end timestamp
			resBytes, err := encode(response)
			if err != nil {
				// todo can I ignore it ？
				log.Printf("encode zerorpc result err:%v, from addr:%v", err, srvSession.remoteAddr)
			}
			errWrite := srvSession.Write(resBytes)
			if errWrite != nil {
				if strings.Contains(errWrite.Error(), "broken pipe") {
					continue
				}
				log.Printf("zerorpc write err:%v", errWrite)
			}
			continue
		}

		// 对数据解码
		rpcData, err := decodeRequest(bytes)
		if err != nil {
			log.Printf("decode err:%v", err)
			response.Err = fmt.Sprintf("rpc request from addr:%s decode err:%v", srvSession.remoteAddr, err)

			response.ResponseTimestamp = time.Now().UnixNano() // invoke end timestamp
			resBytes, err := encode(response)
			if err != nil {
				log.Printf("error encode rpc result err:%v, from addr:%v", err, srvSession.remoteAddr)
			}
			errWrite := srvSession.Write(resBytes)
			if errWrite != nil {
				if strings.Contains(errWrite.Error(), "broken pipe") {
					continue
				}
				log.Printf("error rpc write err:%v", errWrite)
			}
			continue
		}

		// 根据读取到的数据的Name,得到调用的函数名
		f, ok := s.funcs[rpcData.Name]
		if !ok {
			// request methodId not exist
			response.Err = fmt.Sprintf("zerorpc request methodId:%s not exists", rpcData.Name)
			response.StatusCode = 404 // not exist

			response.ResponseTimestamp = time.Now().UnixNano() // invoke end timestamp
			resBytes, err := encode(response)
			if err != nil {
				log.Printf("error encode rpc result err:%v, from addr:%v", err, srvSession.remoteAddr)
			}
			errWrite := srvSession.Write(resBytes)
			if errWrite != nil {
				if strings.Contains(errWrite.Error(), "broken pipe") {
					continue
				}
				log.Printf("error rpc write err:%v", errWrite)
			}
			continue
		}

		// 解析遍历客户端出来的参数, 放到一个数组中
		inArgs := make([]reflect.Value, 0, len(rpcData.Args))
		for _, arg := range rpcData.Args {
			inArgs = append(inArgs, reflect.ValueOf(arg))
		}
		// 反射调用方法，传入参数
		out := f.Call(inArgs)
		// 解析遍历执行结果，放到一个数组中
		response.ResponseTimestamp = time.Now().UnixNano() // invoke end timestamp
		outArgs := make([]interface{}, 0, len(out))
		for _, o := range out {
			outArgs = append(outArgs, o.Interface())
		}
		// 包装数据返回给客户端
		//respRPCData := RPCData{rpcData.Name, outArgs}
		response.Args = outArgs
		response.StatusCode = 0 // success code

		// 编码
		respBytes, err := encode(response)
		if err != nil {
			log.Printf("server rpc data encode err: %v", err)
		}
		// 使用RPC写出数据
		err = srvSession.Write(respBytes)
		if err != nil {
			log.Printf("server rpc session write err: %v", err)
		}
	}
}
